#ifndef __SCCSIMULATOR_H__
#define __SCCSIMULATOR_H__

#include "base/Simulator.h"
#include "mem/SplitBus.h"
#include "util/Pool.h"

class MESICache;
class Directory;
class StatisticsCollection;
class MemController;

class SCCSimulator : public Simulator {
  public:
    NEW_DELETE_OPERATORS_H(SCCSimulator,Simulator);
    SCCSimulator (const char* sysName = NULL);
    virtual ~SCCSimulator ();

    virtual void buildSystem (void* mainX,
                              int argc,
                              const char** argv,
                              const char** envp);

    SplitBus* getBus () {
        return systemBus;
    }

    static uint getBusQueueSize();
    static uint getBusWidth ();
    static uint getBusArbDelay ();
    static uint getCacheSize (uint level, uint default_size=0, bool shared=false);
    static uint getCacheAssoc (uint level, bool shared=false);
    static uint getCacheVictimCacheSize (uint level, bool shared=false);
    static uint getCacheDelay (uint level, bool shared=false);
    static uint getCacheMSHRs (uint level, bool shared=false);

    static bool hasSharedCache ();
    static bool isSharedCacheBanked ();    

  protected:
    SplitBus* systemBus;

    virtual SplitBus*  buildBus ();
    typedef MESICache* (SCCSimulator::*newCacheFunc)(char*, uint, bool, StatisticsCollection*, uint);
    void buildSystem_bus_cached (void* mainX,
                                 int argc,
                                 const char** argv,
                                 const char** envp,
                                 uint _mode);
    
    template<typename BusType> 
    SplitBus* buildNormalBus (); // defined below   

    virtual MESICache* buildPrivateCache (const char* name, 
                                          uint level, 
                                          StatisticsCollection* stats, 
                                          uint snoopDelay);
    virtual MESICache* buildSharedCache (const char* name, 
                                         uint level, 
                                         StatisticsCollection* stats, 
                                         uint snoopDelay,
                                         bool banked = false);
    virtual void hookResetQuiesce ();

    virtual void hookPrintStatistics (FILE* statFile);
    virtual void hookStatsCountVotes ();
    void setCacheStats (uint level, StatisticsCollection* stats);

    static const int NUM_CACHE_BUCKETS = 2;
    Bucket* buckets[NUM_CACHE_BUCKETS];
    static const int NUM_CACHE_COUNTERS = 6;
    Counter* counters[NUM_CACHE_COUNTERS];
};

template<typename BusType> 
SplitBus* SCCSimulator::buildNormalBus () {
    SplitBus* bus = NEW BusType("Bus",
                                TRUE,
                                NULL,
                                global_statistics->addCounter("Bus-Store-Traffic-Bytes"),
                                global_statistics->addCounter("Bus-Load-Traffic-Bytes"),
                                global_statistics->addCounter("Bus-Other-Traffic-Bytes"));
    bus->buildBuses(getBusWidth(), getBusArbDelay(), getBusQueueSize());
    return bus;
}


#endif // __SCCSIMULATOR_H__
